home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / viewers / polyview / plyvw102.lha / PolyView1.02 / pvevent.c < prev    next >
C/C++ Source or Header  |  1990-11-13  |  12KB  |  539 lines

  1.  
  2. #include "pv.h"
  3.  
  4. #define    ESC    27    /* Escape key ASCII code */
  5.  
  6.  
  7. void
  8. handle_events(windows)
  9.     windat_t * windows;
  10. /* DESCRIPTION:  handle_events processes events that are related to the windows
  11. described by the "windows" data structure.  It calls the appropriate window
  12. action function when an event is received.  If the Escape key is pressed, a
  13. pop-up menu is posted confirming the user's desire to terminate the program.
  14. */
  15. {
  16.     long dev_id;
  17.     short data;
  18.     int win_num;
  19.     windat_t * window;
  20.  
  21.  
  22.     /* Loop until the user indicates the desire to quit */
  23.     while (!quit) {
  24.         handle_event(windows);
  25.     }
  26. }
  27.  
  28.  
  29. void
  30. handle_event(windows)
  31.     windat_t * windows;
  32. {
  33.     long dev_id;
  34.     short data;
  35.  
  36.     windat_t * window;
  37.     int animated;
  38.  
  39.  
  40.     /* Clear the global animation flag so that we know whether we've */
  41.     /* already processed at least one of TIMER0 interrupts. */
  42.     animated = FALSE;
  43.  
  44.     /* Clear all of the window "redrawn" flags so that we know which */
  45.     /* are really in need of a redraw */
  46.     for (window = windows; window != NULL; window = window->next) {
  47.         window->redrawn = TRUE;
  48.     }
  49.  
  50.     /* While events are backlogged, keep processing */
  51.     while (qtest()) {
  52.         dev_id = qread(&data);
  53.         switch(dev_id){
  54.         case INPUTCHANGE : 
  55.             if (get_windat(windows, (int) data) != NULL)
  56.                 current.menu_id = (int) data;
  57.             break;
  58.         case KEYBD :
  59.             switch (data) {
  60.             case '+' :
  61.                 forward1(0);
  62.                 break;
  63.             case '-' :
  64.                 reverse1(0);
  65.                 break;
  66.             case 'p' :
  67.             case 'P' :
  68.                 printf("\nat abs %f %f %f\n",
  69.                        at[X], at[Y], at[Z]);
  70.                 printf("from abs %f %f %f %f\n",
  71.                        from[X], from[Y], from[Z], twist/10.0);
  72.                 break;
  73.             case ESC :
  74.                 if (dopup(quit_m) == 100)
  75.                     quit = TRUE;
  76.                 break;
  77.             default :
  78.                 break;
  79.             }
  80.             break;
  81.         case REDRAW :
  82.             window = get_windat(windows, (int) data);
  83.             if (window == NULL) {
  84.                 printf("REDRAW: NULL window encountered\n");
  85.                 printf("    in handle_event.\n");
  86.                 printf("        windows = %ld\n", windows);
  87.                 printf("    window %d\n", (int) data);
  88.             }
  89.             else {
  90.                 window->redrawn = FALSE;
  91.             }
  92.             break;
  93.         case TIMER0:
  94.             /* Animate if necessary */
  95.             if (animation.reverse || animation.forward) {
  96.                 if (!animated) {
  97.                     do_animation(windows);
  98.                     animated = TRUE;
  99.                 }
  100.             }
  101.             break;
  102.         default:
  103.             window = get_windat(windows, (int) current.menu_id);
  104.             if (window != NULL) {
  105.                 (*window->event_fn)(windows, dev_id,
  106.                             current.menu_id);
  107.             }
  108.             else {
  109.                 printf("DEFAULT:  NULL window encountered.\n");
  110.             }
  111.             break;
  112.         }
  113.     }
  114.  
  115.     /* Redraw all of the windows that requested it. */
  116.     for (window = windows; window != NULL; window = window->next) {
  117.         if (!(window->redrawn)) {
  118.             winset((long) window->win_id);
  119.             reshapeviewport();
  120.             (*window->redraw_fn)(window);
  121.             window->redrawn = TRUE;
  122.         }
  123.     }
  124. }
  125.  
  126.  
  127. void
  128. do_animation(windows)
  129.     windat_t * windows;
  130. {
  131.     image_t ** image;
  132.     image_t * old_image;
  133.     windat_t * window;
  134.  
  135.  
  136.     /* Update all view windows with a new dataset */
  137.     for (window = windows; window != NULL; window = window->next) {
  138.         /* If this is not a view window, go to the next one */
  139.         if (window->redraw_fn != image_draw) {
  140.             continue;
  141.         }
  142.  
  143.         /* Clear this window's redrawn flag so that the system */
  144.         /* knows it needs updating.  Set the animated flag so that */
  145.         /* it knows why. */
  146.         window->redrawn = FALSE;
  147.         window->animated = TRUE;
  148.  
  149.         /* Get a pointer to the image data */
  150.         image = (image_t **) &(window->data);
  151.  
  152.  
  153.         /* If animating forward, set up the next frame */
  154.         if (animation.forward) {
  155.             if (animation.forward > 0) {
  156.                 animation.forward--;
  157.             }
  158.             if ((*image)->next == NULL) {
  159.                 *image = images;
  160.             }
  161.             else {
  162.                 *image = (*image)->next;
  163.             }
  164.         }
  165.  
  166.         /* Likewise, if going backward get the previous frame */
  167.         else if (animation.reverse) {
  168.             if (animation.reverse > 0) {
  169.                 animation.reverse--;
  170.             }
  171.  
  172.             old_image = *image;
  173.             if (*image == images) {
  174.                 while ((*image)->next != NULL) {
  175.                     *image = (*image)->next;
  176.                 }
  177.             }
  178.             else {
  179.                 *image = images;
  180.                 while ((*image)->next != old_image) {
  181.                     *image = (*image)->next;
  182.                 }
  183.             }
  184.         }
  185.  
  186.         qenter(REDRAW, (short) window->win_id);
  187.     }
  188. }
  189.  
  190.  
  191. int
  192. do_event(windows, dev_id, data)
  193.     windat_t * windows;
  194.     long dev_id;
  195.     short data;
  196. /* DESCRIPTION:  Processes the event described by "dev_id" and "data"
  197. using the "windows" data structure.  This routine is a catch-all for
  198. non-REDRAW / ESCKEY events.  Returns TRUE if an error occurs, FALSE
  199. otherwise.
  200. */
  201. {
  202.     return FALSE;
  203. }
  204.  
  205.  
  206. int
  207. title_event(windows, dev_id, data)
  208.     windat_t * windows;
  209.     long dev_id;
  210.     short data;
  211. /* DESCRIPTION:  Processes the event described by "dev_id" and "data"
  212. using the "windows" data structure.  Used for the title screen that fills
  213. the view window at program startup.  Any mouse click in the window resets
  214. the event handlers for the window so that it will display and manipulate
  215. the active dataset.
  216. */
  217. {
  218.     windat_t * window;
  219.  
  220.     window = get_windat(windows, (int) data);
  221.     
  222.     switch (dev_id) {
  223.     case LEFTMOUSE:
  224.     case MIDDLEMOUSE:
  225.     case RIGHTMOUSE:
  226.         /* Change the event handlers and redraw the window */
  227.         window->redraw_fn = image_draw;
  228.         window->event_fn = image_event;
  229.         image_draw(window);
  230.  
  231.         /* Unfreeze the window but keep the same aspect */
  232.         keepaspect(NTSC_XSIZ, NTSC_YSIZ);
  233.         winconstraints();
  234.  
  235.         break;
  236.     default:
  237.         break;
  238.     }
  239.     return FALSE;
  240. }
  241.  
  242.  
  243. int
  244. image_event(windows, dev_id, data)
  245.     windat_t * windows;
  246.     long dev_id;
  247.     short data;
  248. /* DESCRIPTION:  Allows the user to "drag" the image around in the
  249. image window by holding down the left or right mouse buttons and
  250. moving the mouse.
  251. */
  252. {
  253.     int i;
  254.     long x,y;
  255.     static float norm[DIMS];
  256.     float scale_v;
  257.     Angle twist_v;
  258.     float rho_v, theta_v, phi_v;
  259.  
  260.     float angleCI;
  261.  
  262.     float CI[DIMS], CP[DIMS], CT[DIMS], CM[DIMS], V[DIMS];
  263.     float magCI, magCM;
  264.     float radius;
  265.  
  266.     float half, old_half;
  267.  
  268.     int both_pressed;
  269.  
  270.     long left, right, bottom, top;    /* Window size parameters */
  271.     float cx, cy;            /* Coordinates of window center */
  272.  
  273.  
  274.     /* If both buttons are pressed (to control the twist parameter), */
  275.     /* then we are apparently re-entering the image event handler. */
  276.     /* Quit before anything gets confused and the calling function */
  277.     /* and the calling function will sort things out. */
  278.     both_pressed = getbutton(LEFTMOUSE) && getbutton(MIDDLEMOUSE);
  279.     if (both_pressed) {
  280.         return FALSE;
  281.     }
  282.  
  283.     /* Process the appropriate button event */
  284.     switch (dev_id) {
  285.     case LEFTMOUSE:
  286.     case MIDDLEMOUSE:
  287.         /* Change active window */
  288.         current.active_id = (int) data;
  289.         current.window = get_windat(windows,
  290.                         (int) current.active_id);
  291.         winset(current.active_id);
  292.  
  293.         /* Get the window size for use later in the loop */
  294.         getorigin(&left, &bottom);
  295.         getsize(&right, &top);
  296.         right += left;
  297.         top += bottom;
  298.         cx = (float) (left + right) / 2.0;
  299.         cy = (float) (bottom + top) / 2.0;
  300.  
  301.                 /* My own "virtual trackball code" */
  302.                 radius = MIN((right-left)/2, (top-bottom)/2);
  303.                 CI[X] = (float) getvaluator(MOUSEX) - cx;
  304.                 CI[Y] = (float) getvaluator(MOUSEY) - cy;
  305.         magCI = fhypot(CI[X], CI[Y]);
  306.  
  307.         if (magCI > radius) {
  308.             CI[X] = radius * CI[X] / magCI;
  309.             CI[Y] = radius * CI[Y] / magCI;
  310.             magCI = radius;
  311.         }
  312.         CI[Z] = fsqrt(radius*radius - magCI*magCI);
  313.  
  314.         V[X] = from[X] - at[X];
  315.         V[Y] = from[Y] - at[Y];
  316.         V[Z] = from[Z] - at[Z];
  317.  
  318.         scale_v = scaling;
  319.         twist_v = twist;
  320.  
  321.         rho_v = rho;
  322.         theta_v = theta;
  323.         phi_v = phi;
  324.  
  325.         for (i = 0; i < DIMS; i++) {
  326.             norm[i] = -(at[i]-from[i])/rho;
  327.         }
  328.  
  329.         half = fsin(phi_v);
  330.  
  331.         /* Loop while button is down, adjusting view on fly */
  332.         while (getbutton(dev_id)) {
  333.             /* Just in case the window changes size */
  334.             reshapeviewport();
  335.             /* For each move ... */
  336.             CM[X] = getvaluator(MOUSEX) - cx;
  337.             CM[Y] = getvaluator(MOUSEY) - cy;
  338.             magCM = fhypot((float)CM[X], (float)CM[Y]);
  339.  
  340.             /* If the cursor has moved outside the */
  341.             /* limit of the "virtual trackball", */
  342.             /* normalize its position to the boundary */
  343.             /* of the circle. */
  344.             if (magCM > radius) {
  345.                 CM[X] = radius * CM[X] / magCM;
  346.                 CM[Y] = radius * CM[Y] / magCM;
  347.                 magCM = radius;
  348.             }
  349.             CM[Z] = fsqrt(radius*radius - magCM*magCM);
  350.  
  351.             if (getbutton(LEFTMOUSE) && getbutton(MIDDLEMOUSE)) {
  352.                 if (!both_pressed) {
  353.                     CT[X] = CI[X]-CP[X];
  354.                     CT[Y] = CI[Y]-CP[Y];
  355.                     CT[Z] = CI[Z]-CP[Z];
  356.                     angleCI = 1800*fatan2(CM[Y], CM[X])/PI;
  357.                     both_pressed = TRUE;
  358.                 }
  359.                 /* Adjust twist using left-right movement */
  360.                 twist = twist_v - (Angle) ((1800 * 
  361.                     fatan2(CM[Y], CM[X])/PI) - angleCI );
  362.             }
  363.             else {
  364.                 if (both_pressed) {
  365.                 CI[X] = CM[X]+CT[X];
  366.                 CI[Y] = CM[Y]+CT[Y];
  367.                 CI[Z] = CM[Z]+CT[Z];
  368.                 twist_v = twist;
  369.                 both_pressed = FALSE;
  370.                 }
  371.  
  372.                 CP[X] = CM[X];
  373.                 CP[Y] = CM[Y];
  374.                 CP[Z] = CM[Z];
  375.  
  376.                 if (dev_id == LEFTMOUSE) {
  377.                 /* Calculate new from point */
  378.                 rho = rho_v + 2.0*(CM[Y]-CI[Y])/radius;
  379.                 if (rho < 0.1) {
  380.                     rho = 0.1;
  381.                 }
  382.  
  383.                 /* Adjust orthographic scaling parameter */
  384.                 scaling = scale_v - 0.02*(CM[Y]-CI[Y])/radius;
  385.                 if (scaling < 0.02) {
  386.                     scaling = 0.02;
  387.                 }
  388.  
  389.                 for (i = 0; i < DIMS; i++) {
  390.                     from[i] = at[i]+norm[i]*rho;
  391.                 }
  392.                 }
  393.  
  394.                 else if (dev_id == MIDDLEMOUSE) {
  395.                 theta = theta_v + PI*(CM[X]-CI[X])/radius;
  396.                 phi = phi_v + PI*(CM[Y]-CI[Y])/radius;
  397.  
  398.                 old_half = half;
  399.                 half = fsin(phi);
  400.  
  401.                 /* If the y axis is crossed, invert the */
  402.                 /* twist value */
  403.                 if (((half >= 0.0) && (old_half < 0.0)) ||
  404.                     ((half <= 0.0) && (old_half > 0.0))) {
  405.                     twist = twist-1800;
  406.                     if (twist < 0) {
  407.                         twist += 3600;
  408.                     }
  409.                     twist_v = twist;
  410.                 }
  411.  
  412.                 sphere_to_cart(rho, theta, phi,
  413.                            &V[X], &V[Y], &V[Z]);
  414.  
  415.                 from[X] = at[X] + V[X];
  416.                 from[Y] = at[Y] + V[Y];
  417.                 from[Z] = at[Z] + V[Z];
  418.                 }
  419.             }
  420.  
  421.             qenter(REDRAW, (short) current.active_id);
  422.             handle_event(windows);
  423.         }
  424.         break;
  425.     case RIGHTMOUSE :
  426.         current.active_id = (int) data;
  427.         current.window = get_windat(windows,
  428.                         (int) current.active_id);
  429.         switch(dopup(view_m)) {
  430.         case 7:    /* Fly */
  431.             do_fly(7);
  432.             break;
  433.         case 8: /* Pop */
  434.             do_pop(8);
  435.             break;
  436.         case 9:    /* Redraw */
  437.             do_redraw(9);
  438.             break;
  439.         case 10: /* Reset */
  440.             do_reset(10);
  441.             break;
  442.         case 11: /* Write HDF */
  443.             write_hdf(11);
  444.             break;
  445.         default:
  446.             break;
  447.         }
  448.         break;
  449.     default :
  450.         break;
  451.     }
  452.  
  453.     return FALSE;
  454. }
  455.  
  456.  
  457. int
  458. palette_event(windows, dev_id, data)
  459.     windat_t * windows;
  460.     long dev_id;
  461.     short data;
  462. /* DESCRIPTION:  Allows the user to change the palette through a pop
  463. up menu.  Also can press ESC key to get an exit menu.
  464. */
  465. {
  466.     long x,y;
  467.     float old_origin, old_slope;
  468.     float slope_p;
  469.     
  470.     switch (dev_id) {
  471.     case LEFTMOUSE:
  472.     case MIDDLEMOUSE:
  473.         x = getvaluator(MOUSEX);
  474.         y = getvaluator(MOUSEY);
  475.         old_origin = origin;
  476.         old_slope = slope;
  477.  
  478.         while (getbutton(dev_id)) {
  479.             /* Just in case the window changes size */
  480.             reshapeviewport();
  481.  
  482.             /* Adjust slope of mapping function */
  483.             slope_p = slope;
  484.             slope = fexp(flog(old_slope) +
  485.                 (getvaluator(MOUSEX)-x)/50.0);
  486.             if (slope < 1.0/512.0) slope = 1.0/512.0;
  487.             if (slope > 255.0) slope = 255.0;
  488.  
  489.             /* Adjust old origin to account for shift */
  490.             /* in slope */
  491.             old_origin -= (slope - slope_p) * 128;
  492.  
  493.             /* Adjust origin of mapping function */
  494.             origin = old_origin +
  495.                 (getvaluator(MOUSEY)-y);
  496.  
  497.             /* Update the color map */
  498.             build_colormap(MAP_SPEC);
  499.         }
  500.         break;
  501.  
  502.     case RIGHTMOUSE :
  503.         dopup(vpalette_m);
  504.         break;
  505.  
  506.     default :
  507.         break;
  508.     }
  509.     
  510.     return FALSE;
  511. }
  512.  
  513.  
  514. void
  515. init_events(windows)
  516.     windat_t * windows;
  517. /* DESCRIPTION:  init_events queues devices for input, and queues the initial
  518. input events for all of the "windows".
  519. */
  520. {
  521.     windat_t * current;
  522.  
  523.     /* Queue only redraw events.  Also, if the user presses the escape */
  524.     /* key, we want to know. */
  525.     qdevice(ESCKEY);
  526.     qdevice(KEYBD);
  527.     qdevice(REDRAW);
  528.     qdevice(LEFTMOUSE);
  529.     qdevice(MIDDLEMOUSE);
  530.     qdevice(RIGHTMOUSE);
  531.     qdevice(TIMER0);
  532.     noise(TIMER0, 15);
  533.  
  534.     /* Place events in the queue to redraw all of the windows. */
  535.     for (current=windows; current != NULL; current=current->next) {
  536.         qenter(REDRAW, (short) current->win_id);
  537.     }
  538. }
  539.